package cc.verywell.pureblock.util.sign;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import cc.verywell.pureblock.log.Pblog;

/**
* 
*
* @author TanYaqiu 
* @address flat 601
* @date 2019年3月2日 下午2:22:39
*/
public class RsaSave implements Callable<RsaServer> {
	
	final private Path filePath;
	final private Aes128 aes;
	public RsaSave(Path filePath, byte[] storePassword) {
		this.filePath = filePath;
		this.aes = new Aes128(Arrays.copyOf(new Sha().hash(storePassword),16));
	}
	
	@Override
	public RsaServer call() throws Exception {
		boolean isReadableFile = false;
		try {
			isReadableFile = Files.isRegularFile(filePath) && Files.isReadable(filePath);
		}catch(Exception e) {
			throw new IOException("file ["+filePath+"] cannot see!",e);
		}
		if(isReadableFile) {
			return readExists();
		}else if(!Files.exists(filePath)){
			return createNew();
		}else {
			throw new IOException("file ["+filePath+"] cannot read!");
		}
	}
	
	RsaServer readExists() throws Exception{
		long fileLenth = Files.size(filePath);
		if(fileLenth>1024*1024) {
			throw new IOException("Key store file ["+filePath+"], size:"+fileLenth+" that is too big.");
		}
		try(AsynchronousFileChannel afc = AsynchronousFileChannel.open(filePath,StandardOpenOption.READ);){
			if(Pblog.IO)Pblog.IO("read RSA key store from exists file.");
			ByteBuffer bb = ByteBuffer.allocate((int)fileLenth);
			Future<Integer> f = afc.read(bb, 0);
			f.get();
			bb.flip();
			aes.decode(bb);
			return RsaServer.load(bb);
		}
	}
	
	RsaServer createNew() throws Exception{
		Files.createDirectories(filePath.getParent());
		RsaServer rs = new RsaServer();
		ByteBuffer bb = ByteBuffer.allocate(aes.outputLength(rs.saveLength()));
		rs.save(bb);
		bb.flip();
		aes.encode(bb);
		try(AsynchronousFileChannel afc = AsynchronousFileChannel.open(filePath,StandardOpenOption.CREATE,StandardOpenOption.WRITE);){
			if(Pblog.SECURE)Pblog.SECURE("crate new RSA key store.");
			Future<Integer> f = afc.write(bb, 0);
			f.get();
		}
		return rs;
	}
	
	
	
}
